package com.android.base_network.interceptor

import android.annotation.SuppressLint
import android.text.TextUtils
import com.android.base_network.BuildConfig
import com.android.base_network.CacheKeys
import com.android.base_network.HeaderKeys
import com.blankj.utilcode.util.LogUtils
import com.blankj.utilcode.util.SPUtils
import com.blankj.utilcode.util.TimeUtils
import com.jeremyliao.liveeventbus.LiveEventBus
import okhttp3.*
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import org.json.JSONException
import org.json.JSONObject
import java.io.IOException
import java.util.*


class TokenInterceptor : Interceptor {

    override fun intercept(chain: Interceptor.Chain): Response {
        val request: Request = chain.request()
        synchronized(this) {

            // 请求头里的 token
            val token: String? = request.headers[HeaderKeys.authorization]
            // token 不为空，则传递了 token
            if (!TextUtils.isEmpty(token)) {
                // 如果token过期 再去重新请求token 然后设置token的请求头 重新发起请求 用户无感
                if (isTokenExpired()) {
                    val newHeaderToken: String = getNewToken()
                    if (!TextUtils.isEmpty(newHeaderToken)) {
                        // 使用新的Token，创建新的请求
                        val newRequest: Request = request.newBuilder()
                            .removeHeader(HeaderKeys.authorization)
                            .addHeader(HeaderKeys.authorization, newHeaderToken)
                            .build()
                        return chain.proceed(newRequest)
                    }
                }
                // 多个接口同时调用时，传过来的 token 可能已经失效。重新获取传递过去
                val build: Request = request.newBuilder()
                    .removeHeader(HeaderKeys.authorization)
                    .addHeader(HeaderKeys.authorization, getToken())
                    .build()
                return chain.proceed(build)
            }

        }
        return chain.proceed(request.newBuilder().build())

    }

    private fun getToken(): String {
        // 本地 token
        return SPUtils.getInstance().getString(CacheKeys.token)
    }


    private var updateTime: Long = 24 * 60 * 60 * 30

    private val validTime = 24 * 60 * 60 * 15

    /**
     * 根据本地时间判断是否需要重新获取 token
     * @return 是否调用重新获取 token 接口
     */

    private fun isTokenExpired(): Boolean {
        // 本地时间判断什么时候刷新
        try {
            val oldToken: String = SPUtils.getInstance().getString(CacheKeys.token)
            LogUtils.i("old token:$oldToken")
            val newTime = TimeUtils.getNowMills() / 1000
            // 获取到 token 的时间
            val tokenTime = SPUtils.getInstance().getLong(CacheKeys.tokenTime, 0L)

            // 间隔时间
            val timeInterval = newTime - tokenTime
            LogUtils.i("时间差：" + timeInterval + "s   有效期：" + updateTime + "s   有效时间：" + validTime + "s")
            return if (timeInterval < updateTime) {
                // 在有效期
                if (timeInterval < validTime) {
                    // token 还能用直接请求
                    LogUtils.i("无需更新 token，有效期内")
                    false
                } else {
                    // 获取新的 token
                    LogUtils.i("需要更新 token")
                    true
                }
            } else {
                // 已过期 不用换 token 需要重新登录
                LogUtils.i("重新登录，token 失效，不更新")
                saveToken("")
                false
            }

        } catch (e: Exception) {
            e.printStackTrace()
            return true
        }
    }

    /**
     * 获取新的 token
     */
    @SuppressLint("CheckResult")
    @Throws(IOException::class)
    private fun getNewToken(): String {
        val requestBody: RequestBody =
            RequestBody.create("application/json; charset=utf-8".toMediaTypeOrNull(), "")
        val request: Request = Request.Builder()
            .url(BuildConfig.base_url + "/v3/login/refreshToken")
            .post(requestBody)
            .build()
        val okHttpClient = OkHttpClient()
        val call: Call = okHttpClient.newCall(request)
        val string: String = Objects.requireNonNull(call.execute().body)?.string() ?: ""
        LogUtils.i(string)
        try {
            val jsonObject = JSONObject(string)
            val code: Int = jsonObject.getInt("code")
            if (code == 200) {
                val data: JSONObject = jsonObject.getJSONObject("data")
                val expiresIn: Long = data.getLong("expirationTime")
                val userToken: String = data.getString("authorization")
                saveToken(userToken)
                return userToken
            }
        } catch (e: JSONException) {
            e.printStackTrace()
        }
        return ""
    }


    /**
     * 保存 token
     * @param userToken
     * token
     */
    private fun saveToken(userToken: String) {
        LogUtils.i("保存新的 token：$userToken")

        LiveEventBus.get<String>(CacheKeys.token).post(userToken)
        SPUtils.getInstance().put(CacheKeys.token, userToken)
        SPUtils.getInstance().put(CacheKeys.tokenTime, TimeUtils.getNowMills() / 1000)
    }
}